﻿using System;
using System.Collections.Generic;
using System.Linq;
using Codingly.NRex;
using NRex.Logging;

namespace NRex
{
    internal class ReferencedAssembliesLister : AbstractReferencesLister
    {
        public ReferencedAssembliesLister(ILogger logger)
            : base(logger)
        {
        }

        public void ProcessTarget(string fileOrDirectory)
        {
            GetAssemblies(fileOrDirectory);
            if (Assemblies.Count() == 0)
                return;

            PrintReferencedAssemblies();
        }

        protected void PrintReferencedAssemblies()
        {
            var referencedAssembliesDictionary = new SortedDictionary<string, IList<ReferencedAssembly>>();

            foreach (var assembly in Assemblies)
            {
                foreach (var referencedAssembly in assembly.GetReferencedAssemblies())
                {
                    if (!referencedAssembliesDictionary.ContainsKey(referencedAssembly.Name))
                        referencedAssembliesDictionary.Add(referencedAssembly.Name, new List<ReferencedAssembly>());

                    referencedAssembliesDictionary[referencedAssembly.Name].Add(
                        new ReferencedAssembly(assembly.GetName().Name,
                                               referencedAssembly.Version));
                }
            }

            foreach (var keyValuePair in referencedAssembliesDictionary)
            {
                var previousVersion = keyValuePair.Value.First().ReferencedVersion;
                var conflictExists =
                    keyValuePair.Value.Any(referencedAssembly => referencedAssembly.ReferencedVersion != previousVersion);
                if (conflictExists)
                    Logger.Warn("{0} is referenced by", keyValuePair.Key);
                else
                    Logger.Info("{0} is referenced by", keyValuePair.Key);

                foreach (var referencedAssembly in keyValuePair.Value)
                {
                    Logger.Info("\t{0} in version {1}", referencedAssembly.ReferencedBy,
                                 referencedAssembly.ReferencedVersion);
                }
            }
        }

        private class ReferencedAssembly
        {
            public ReferencedAssembly(string assemblyName, Version version)
            {
                ReferencedBy = assemblyName;
                ReferencedVersion = version;
            }

            public string ReferencedBy { get; private set; }
            public Version ReferencedVersion { get; private set; }
        }
    }
}